/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.common.utils;

import cn.hutool.core.date.DateUtil;
import liquibase.pro.packaged.V;
import lombok.AllArgsConstructor;
import org.springblade.common.constant.CommonConstant;
import org.springblade.common.constant.RedisKeyConstant;
import org.springblade.common.constant.TenantConstant;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springblade.core.tool.utils.DigestUtil;
import org.springblade.modules.auth.utils.TokenUtil;
import org.springblade.modules.personal.entity.SecrecyLevel;
import org.springblade.modules.personal.entity.UserBaseEntity;
import org.springblade.modules.personal.service.IUserBaseService;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.service.IRoleService;
import org.springblade.modules.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;

import static org.springblade.common.constant.RedisKeyConstant.*;
import static org.springblade.common.constant.TrainingRoleConstant.*;

/**
 * 通用工具类
 *
 * @author Chill
 */
@Component
public class CommonUtil {

	@Autowired
	private  BladeRedis bladeRedis;
	@Autowired
	private  IUserBaseService userBaseService;
	@Autowired
	private  IRoleService roleService;
	@Autowired
	private  IUserService userService;

	@Value("${jxc.role}")
	private String roleId;

	/**
	 * 获取用户扩展表信息
	 */
	public UserBaseEntity getUserBaseEntity(){
		Long userId=AuthUtil.getUserId();
		UserBaseEntity entity = bladeRedis.get(RedisKeyConstant.USER_BASE_KEY_PREFIX + userId);
		if (null==entity){
			initUserBaseCache(userId);
			return getUserBaseEntity();
		}
		return entity;
	}

	public UserBaseEntity createUser(String idcard,String userName){
		UserBaseEntity userBaseEntity = userBaseService.selectByIdcard(idcard);
		if (null==userBaseEntity && null!=idcard){//如果没有此用户，则直接注册
			User bladeUser=new User();
			bladeUser.setAccount(idcard);
			bladeUser.setRoleId(roleId);//默认为受训人员
			bladeUser.setTenantId(TokenUtil.DEFAULT_TENANT_ID);
			bladeUser.setRealName(userName);
			bladeUser.setName(userName);
			bladeUser.setPassword(DigestUtil.encrypt(CommonConstant.DEFAULT_PASSWORD));
			userService.save(bladeUser);

			userBaseEntity=new UserBaseEntity();
			userBaseEntity.setUserNumber(idcard);
			userBaseEntity.setIdCard(idcard);
			userBaseEntity.setUserId(bladeUser.getId());
			userBaseEntity.setUserName(userName);

			userBaseEntity.setIntegral((float) 0);
			userBaseEntity.setPeriod((float) 0);
			userBaseService.save(userBaseEntity);
		}
		return userBaseEntity;
	}

	public void initUserBaseCache(Long userId){
		UserBaseEntity entity=userBaseService.selectByUserId(userId);
		if (null==entity) {
			throw new ServiceException("为找到该用户的扩展信息!userId:"+userId);
		}
		bladeRedis.setEx(USER_BASE_KEY_PREFIX+userId,entity,USER_BASE_KEY_PREFIX_EXPIRE);
	}


	/**
	 * 获取用户角色
	 */
	public List<String> getRoleAliases(){
		String roleId= AuthUtil.getUser().getRoleId();
		List<String> roleAliases = bladeRedis.get(RedisKeyConstant.USER_ROLE_ALIAS_KEY_PREFIX + roleId);
		if (null==roleAliases){
			roleAliases = roleService.getRoleAliases(roleId);
			bladeRedis.setEx(USER_ROLE_ALIAS_KEY_PREFIX+roleId,roleAliases,USER_ROLE_ALIAS_KEY_EXPIRE);
		}
		//获取当前用户角色别名
		return roleAliases;
	}

	/**
	 * startTime 起始日
	 * days 天数
	 * 获取截止时间的时间戳
	 */
	public static Date getEndTime(Date startTime,int days){
		long endTime=startTime.getTime() + 60 * 60 * 24 * 1000 * days;
		return new Date(endTime);
	}

	/**
	 * 部分资源用户只能看到自己的，指定角色可以看到所有
	 * 或者部分资源只能给特定角色看
	 */
	public boolean checkRoleAlias(String roleAlias){
		List<String> roleAliases = getRoleAliases();
		if (CollectionUtil.isEmpty(roleAliases)) return false;
		if (roleAliases.contains(roleAlias)) {
			return true;
		}
		return false;
	}


	/**
	 * 部分资源用户只能看到自己创建的，指定角色可以看到所有
	 * roleAlias指定的角色
	 */
	public void checkRoleAliasPermission(Object son,Class sonClass){
		String paramName="createUser";
		Long value=AuthUtil.getUserId();
		String[] roleAlias=new String[]{Administrator,ADMIN,TEST};
		List<String> roleAliasesList = getRoleAliases();
		boolean flag=false;
		for (String item:roleAliasesList) {
			for (String str:roleAlias){
				if (item.equals(str)) {
					flag=true;
					break;//满足一种角色即可退出
				}
				if (flag) break;
			}
		}

		if (!flag){//该用户角色不满足指定的角色
			setBaseEntityValue(son,sonClass,paramName,value);
		}
	}


	/**
	 * 修改BaseEntity的私有变量值
	 * 此项目的BaseEntity是爷爷类
	 */
	public void setBaseEntityValue(Object son,Class sonClass ,String paramName, Long value){
		Field field = null;
		Class serviceClass=sonClass;
		int num=0;
		while (true){
			try {
				field = serviceClass.getDeclaredField(paramName);
				field.setAccessible(true);
				field.set(son, value);
				if (num==5) break; //五层没找到则直接返回
				break;
			} catch (NoSuchFieldException e) {
				serviceClass=serviceClass.getSuperclass();
				num++;
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}


	/**
	 * 获取导入批次号
	 */
	public static String getImportVersion(){
		return DateUtil.format(new Date(),"yyyyMMddHHmmss");
	}

	public static UserBaseEntity getInitUserBaseEntity(){
		UserBaseEntity userBaseEntity=new UserBaseEntity();
		userBaseEntity.setSecrecyLevel(SecrecyLevel.NORMAL.getCode());
		userBaseEntity.setIntegral((float) 0);
		userBaseEntity.setPeriod((float) 0);
		return userBaseEntity;
	}

}
